package org.keyroy.tag;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

public class Tag {
	private static final String NULL = "null";
	protected static final String STR_NAME = "t";
	protected static final String STR_TAG = "s";

	protected String text;
	protected String name;
	protected Tag parent;
	protected List<Tag> tags = new ArrayList<Tag>();
	protected Hashtable<String, String> parameters = new Hashtable<String, String>();

	public Tag() {
		name = NULL;
	}

	public Tag(String string) {
		this();
		Tag tag = XmlSAX.parseTag(string);
		if (tag != null) {
			copy(tag);
		} else {
			throw new IllegalArgumentException();
		}
	}

	public Tag(InputStream inputStream) {
		this();
		Tag tag = XmlSAX.parseTag(inputStream);
		if (tag != null) {
			copy(tag);
		} else {
			throw new IllegalArgumentException();
		}
	}

	public Tag(XmlSupport xmlSupport) {
		this();
		if (xmlSupport != null) {
			setName(xmlSupport.getTagName());
			xmlSupport.initTag(this);
		}
	}

	public void copy(Tag tag) {
		this.tags = tag.tags;
		this.parameters = tag.parameters;
		this.text = tag.text;
		this.name = tag.name;
		this.parent = tag.parent;
	}

	public final void setName(String nameString) {
		this.name = nameString;
	}

	public final boolean isName(String nameString) {
		return this.name.equals(nameString);
	}

	public final void setText(String textString, boolean validateValue) {
		if (validateValue) {
			this.text = textString;
		}
	}

	public final void setText(String textString) {
		this.text = textString;
	}

	public final String getName() {
		return name;
	}

	public final Tag getParent() {
		return parent;
	}

	public final String getText() {
		return text;
	}

	public XmlSupport toObject(Class<? extends XmlSupport> xmlSupportClass) {
		try {
			XmlSupport xmlSupport = xmlSupportClass.newInstance();
			xmlSupport.initObj(this);
			return xmlSupport;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public final XmlSupport getObject(Class<? extends XmlSupport> xmlSupportClass) {
		return toObject(xmlSupportClass);
	}

	public final void fillObject(XmlSupport xmlSupport) {
		xmlSupport.initObj(this);
	}

	public final XmlSupport getChildObject(String tagName, Class<? extends XmlSupport> xmlSupportClass) {
		Tag tag = getChildTag(tagName);
		if (tag != null) {
			return tag.toObject(xmlSupportClass);
		}
		return null;
	}

	public final XmlSupport getChildObject(Class<? extends XmlSupport> xmlSupportClass) {
		try {
			XmlSupport xmlSupport = xmlSupportClass.newInstance();
			Tag tag = getChildTag(xmlSupport.getTagName());
			if (tag != null) {
				xmlSupport.initObj(tag);
				return xmlSupport;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public final Tag getChildTag(final String tagName) {
		for (int i = 0; i < tags.size(); i++) {
			Tag tag = tags.get(i);
			if (tagName == null) {
				return tag;
			} else if (tag.isName(tagName)) {
				return tag;
			}
		}
		return null;
	}

	public List<Tag> getChildTagArray() {
		return tags;
	}

	public List<Tag> getChildTagArray(String name) {
		if (name == null) {
			return tags;
		} else {
			List<Tag> rTags = new ArrayList<Tag>();
			for (int i = 0; i < tags.size(); i++) {
				Tag cTag = tags.get(i);
				if (name.equals(cTag.getName())) {
					rTags.add(cTag);
				}
			}
			return rTags;
		}
	}

	public List<XmlSupport> getChildObjectArray(Class<? extends XmlSupport> xmlSupportClass) {
		ArrayList<XmlSupport> xmlSupports = new ArrayList<XmlSupport>(tags.size());
		try {
			String name = xmlSupportClass.newInstance().getTagName();
			for (int i = 0; i < tags.size(); i++) {
				Tag tag = tags.get(i);
				if (tag.getName().equals(name)) {
					try {
						XmlSupport xmlSupport = tag.toObject(xmlSupportClass);
						if (xmlSupport != null) {
							xmlSupports.add(xmlSupport);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return xmlSupports;
	}

	@SuppressWarnings( { "unchecked" })
	public void getChildObjectArray(Class<? extends XmlSupport> xmlSupportClass, List list) {
		try {
			String name = xmlSupportClass.newInstance().getTagName();
			for (int i = 0; i < tags.size(); i++) {
				Tag tag = tags.get(i);
				if (tag.getName().equals(name)) {
					try {
						XmlSupport xmlSupport = tag.toObject(xmlSupportClass);
						if (xmlSupport != null) {
							list.add(xmlSupport);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void addStrings(String name, List<String> strings) {
		Tag tag = new Tag();
		tag.setName(name);
		for (int i = 0; i < strings.size(); i++) {
			Tag child = new Tag();
			child.setName(STR_TAG);
			child.addParameter(STR_NAME, strings.get(i));
			tag.addChild(child);
		}
		addChild(tag);
	}

	public void getStrings(String name, List<String> strings) {
		Tag tag = getChildTag(name);
		List<Tag> cTags = tag.getChildTagArray();
		for (int i = 0; i < cTags.size(); i++) {
			String str = cTags.get(i).getParameterValue(STR_NAME);
			if (str != null) {
				strings.add(str);
			}
		}
	}

	public final String getParameterValue(String key) {
		return parameters.get(key);
	}

	public final int getParameterIntValue(String key) {
		return getParameterIntValue(key, 0);
	}

	public final int getParameterIntValue(String key, int def) {
		try {
			return Integer.parseInt(parameters.get(key));
		} catch (Exception e) {
		}
		return def;
	}

	public final long getParameterLongValue(String key) {
		try {
			return Long.parseLong(parameters.get(key));
		} catch (Exception e) {
		}
		return 0l;
	}

	public final float getParameterFloatValue(String key) {
		try {
			return Float.parseFloat(parameters.get(key));
		} catch (Exception e) {
		}
		return 0.0f;
	}

	public final double getParameterDoubleValue(String key) {
		try {
			return Double.parseDouble(parameters.get(key));
		} catch (Exception e) {
		}
		return 0.0f;
	}

	public final boolean getParameterBooleanValue(String key) {
		try {
			return Boolean.parseBoolean(parameters.get(key));
		} catch (Exception e) {
		}
		return false;
	}

	public void addChild(Tag tag) {
		if (tag != null && tag.equals(this) == false) {
			tags.add(tag);
		}
	}

	public void addChild(List<? extends XmlSupport> xmlSupports) {
		if (xmlSupports != null && xmlSupports.size() > 0) {
			for (int i = 0; i < xmlSupports.size(); i++) {
				addChild(xmlSupports.get(i));
			}
		}
	}

	public void addChild(Enumeration<? extends XmlSupport> xmlSupports) {
		if (xmlSupports != null) {
			while (xmlSupports.hasMoreElements()) {
				addChild((XmlSupport) xmlSupports.nextElement());
			}
		}
	}

	public void addChild(XmlSupport xmlSupport) {
		if (xmlSupport != null) {
			addChild(new Tag(xmlSupport));
		}
	}

	public final void addParameter(String key, Object value) {
		parameters.put(key, String.valueOf(value));
	}

	public final void addParameter(String key, String value) {
		parameters.put(key, value);
	}

	public final void addParameter(String key, Object value, boolean validateValue) {
		if (validateValue) {
			addParameter(key, value);
		}
	}

	public String toFormateString() {
		return toFormateString(0, true);
	}

	protected String toFormateString(int indent, boolean isBreakLine) {
		final char LF = '\r';
		StringBuffer stringBuffer = new StringBuffer();
		if (isBreakLine) {
			String indentString = getIndent(indent);
			stringBuffer.append(indentString);
		}
		stringBuffer.append("<" + name);

		if (parameters.size() > 0) {
			Enumeration<String> keys = parameters.keys();
			Enumeration<String> values = parameters.elements();
			String key = null;
			String value = null;
			while (values.hasMoreElements()) {
				key = keys.nextElement();
				value = values.nextElement();
				stringBuffer.append(' ');
				stringBuffer.append(key + "=" + "\"" + value + "\"");
			}
		}

		if (tags.size() == 0 && text == null) {
			stringBuffer.append("/>");
			if (isBreakLine) {
				stringBuffer.append(LF);
			}
		} else {
			stringBuffer.append('>');
			if (isBreakLine) {
				stringBuffer.append(LF);
			}
			if (text != null && text.length() > 0) {
				stringBuffer.append(text);
				if (isBreakLine) {
					stringBuffer.append(LF);
				}
			}
			for (int i = 0; i < tags.size(); i++) {
				stringBuffer.append(tags.get(i).toFormateString(indent + 4, isBreakLine));
			}
			if (isBreakLine) {
				String indentString = getIndent(indent);
				stringBuffer.append(indentString);
			}
			stringBuffer.append("</" + name + ">");
			if (isBreakLine) {
				stringBuffer.append(LF);
			}
		}
		return stringBuffer.toString();
	}

	private String strIndent;

	protected String getIndent(int indent) {
		if (strIndent != null && strIndent.length() == indent) {
			return strIndent;
		}
		StringBuffer stringBuffer = new StringBuffer();
		for (int i = 0; i < indent; i++) {
			stringBuffer.append(' ');
		}
		strIndent = stringBuffer.toString();
		return strIndent;
	}

	public String toString() {
		return toFormateString(0, false);
	}
}
